﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;

using TLL.Finance.Currencys;
using TLL.Log;
using TLL.UTL;

using TasksLog.Conf;

namespace TasksLog.Statistics
{
    public enum InitializeType : int
    {
        Data = 0,
        Diagram = 1,
        ValuesDiagram = 2,
        Detail = 3,
    }
    public partial class Statistic : Form
    {
        private bool MouseClick = false;
        private Point MouseClickPosition;

        private double MaxValue = 0;
        private Dictionary<CurrencyType, double> MaxValues = new Dictionary<CurrencyType,double>();
        private Loader Loader = null;
        private DateTime MaxDate = DateTime.MinValue;
        private DateTime MinDate = DateTime.MaxValue;
        private bool FirstInitialize = true;
        private double Height {
            get {
                return (PBDiagram.Height - 15) / this.MaxValue;
            }
        }
        private List<LogDate> DrowingElements = null;
        private List<LogItem> Logs = new List<LogItem>();
        public Statistic()
        {
            InitializeComponent();
            //this.StartPosition = FormStartPosition.CenterScreen;
            Initialize(InitializeType.Data);
            CBValues.SelectedIndex = 0;
        }
        private void InitializeDate(List<string> urls)
        {
            Logs = new List<LogItem>();
            urls.Add(Directory.GetFiles(Parametrs.LogsFolderURL).FirstOrDefault());
            urls.Add(Parametrs.LogURL);
            foreach (var url in urls)
                using (var repository = new LogRepository(url, Parametrs.DebugURL, null))
                    if (repository.Access)
                        Logs.AddRange(repository.Get());


            var data = new Dictionary<DateTime, LogTime>();
            foreach (var item in Logs.GroupBy(x => DateTime.Parse(x.Create.ToShortDateString())).OrderBy(x => x.Key))
            {
                var time = LogTime.Empty;
                foreach (var logitem in item)
                {
                    var currenttime = LogTime.Empty;
                    if (logitem.Log != null)
                        foreach (var timeitem in logitem.Log)
                            time.Add(timeitem.Time);
                }
                data.Add(item.Key, time);
            }
        }
        private void InitializeDiagram()
        {

            if (FirstInitialize)
            {
                var date = new LogDate(0, DateTime.Now, null);
                date.Date = DateTime.Parse(string.Format("{0}.{1}.{2}", 1, date.Date.Value.Month, date.Date.Value.Year));
                DTPFrom.Value = date.Date.Value;
                FirstInitialize = false;
            }

            var itemslog = Logs.Select(x => x.Log).ToList();
            var alllogs = new List<LogDate>();
            foreach (var item in itemslog)
                if (item != null)
                    alllogs.AddRange(item);


            var groupLogs = alllogs.GroupBy(x => x.Date);
            for (int i = 0; i < (DTPTo.Value - DTPFrom.Value).TotalDays; i++ )
            {
                var currDate = DTPFrom.Value.AddDays(i);
                var item = groupLogs
                    .FirstOrDefault(x => x.Key.Value == currDate);
                if (item == null)
                {
                    if (DrowingElements == null)
                        DrowingElements = new List<LogDate>();
                    DrowingElements.Add(new LogDate(0, currDate, new LogTime()));
                }
                else
                {
                    var elements = new List<LogDate>();
                    foreach (var alowitem in item)
                        elements.Add(alowitem);

                    if (DrowingElements == null)
                        DrowingElements = new List<LogDate>();
                    DrowingElements.AddRange(elements);
                }
            }

            PBDiagram.Invalidate();
        }
        private void InitializeValuesDiagram()
        {
            PBCashValue.Invalidate();
            PBDate.Invalidate();
        }
        private void InitializeDetail()
        {
            var allTime = LogTime.Empty;

            if (DrowingElements != null)
            {
                foreach (var item in DrowingElements.GroupBy(x=>x.Date))
                    foreach (var subitem in item)
                        allTime.Add(subitem.Time);
            }
            var money = Money.Calculate(
                        allTime,
                        MainConf.Setting.CashPerH,
                        MainConf.Currencys,
                        MainConf.Setting.CurrencyType);

            LbDetail.Text = "All: Time = {0};    USD({1})     UAH({2})     RUB({3})";

            LbDetail.Text = LbDetail.Text
                .Replace("{0}", LogTime.Formated(allTime))
                .Replace("{1}", money.FirstOrDefault(x => x.Key == CurrencyType.USD).Value.ToString("0.00"))
                .Replace("{2}", money.FirstOrDefault(x => x.Key == CurrencyType.UAH).Value.ToString("0.00"))
                .Replace("{3}", money.FirstOrDefault(x => x.Key == CurrencyType.RUB).Value.ToString("0.00"));
        }
        private void Initialize(List<InitializeType> Types)
        {
            if (Loader == null)
                Loader = new Loader(this, LoaderType.Diagram);

            Loader.Start();
            foreach (var type in Types)
                switch(type)
                {
                    case InitializeType.Data         : InitializeDate(Directory.GetFiles(Parametrs.LogsFolderURL).ToList<string>()); break;
                    case InitializeType.Detail       : InitializeDetail(); break;
                    case InitializeType.Diagram      : InitializeDiagram(); break;
                    case InitializeType.ValuesDiagram: InitializeValuesDiagram(); break;
                }
            Loader.Stop();
        }
        private void Initialize(InitializeType type)
        {
            if (Loader == null)
                Loader = new Loader(this, LoaderType.Diagram);

            Loader.Start();
            switch(type)
            {
                case InitializeType.Data         : InitializeDate(Directory.GetFiles(Parametrs.LogsFolderURL).ToList<string>()); break;
                case InitializeType.Detail       : InitializeDetail(); break;
                case InitializeType.Diagram      : InitializeDiagram(); break;
                case InitializeType.ValuesDiagram: InitializeValuesDiagram(); break;
            }
            Loader.Stop();
        }
        private void ClearValuesDiagram()
        {
            DrowingElements = null;

            LbDetail.Text = "All: Time = 0;    USD(0)     UAH(0)     RUB(0)";
        }


        private void PBDiagram_Paint(object sender, PaintEventArgs e)
        {
            e.Graphics.DrawLine(new Pen(Color.Black, 1), new Point(5, PBDiagram.Height), new Point(5, 0));
            e.Graphics.DrawLine(new Pen(Color.Black, 1), new Point(0, PBDiagram.Height - 5), new Point(PBDiagram.Width, PBDiagram.Height - 5));

            if (DrowingElements != null)
            {
                var width = (PBDiagram.Width - 15) / DrowingElements.GroupBy(x => x.Date.Value.ToShortDateString()).Count();
                int index = 0;


                foreach (var item in DrowingElements.GroupBy(x => DateTime.Parse(x.Date.Value.ToShortDateString())))
                {
                    var time = new LogTime();
                    foreach (var dateitem in item)
                        time.Add(dateitem.Time);

                    Dictionary<CurrencyType, double> currency = Money.Calculate(
                                    time,
                                    MainConf.Setting.CashPerH,
                                    MainConf.Currencys,
                                    MainConf.Setting.CurrencyType);

                    var money = currency.FirstOrDefault(x => x.Key == Utilities.GetEnum<CurrencyType>((string)CBValues.SelectedItem)).Value;

                    var value = this.MaxValue != 0 ? int.Parse((money * this.Height).ToString().Split(new char[] { ',', '.' })[0]) : 0;

                    var verticalStep = PBDiagram.Height / 10;

                    e.Graphics.FillRectangle(
                        GetBrush(value, true),
                        new Rectangle(
                            width * index + 6,
                            PBDiagram.Height - 5 - value,
                            width - 3,
                            value
                            ));
                    e.Graphics.DrawLine(new Pen(Color.Silver), new Point(width * index + 6, 0), new Point(width * index + 6, PBDiagram.Height));
                    if (index < 11)
                        e.Graphics.DrawLine(new Pen(Color.Silver), new Point(0, verticalStep * index), new Point(PBDiagram.Width, verticalStep * index));
                    index++;
                }
            }
        }
        private Brush GetBrush(int value, bool calibrate)
        {
            if (calibrate)
                value = int.Parse((value / this.Height).ToString().Split(new char[] {'.',','})[0]);
            else
                value = int.Parse(value.ToString().Split(new char[] { '.', ',' })[0]);
            if (value <= this.MaxValue / 10)
                return Brushes.DarkRed;
            else if (value > this.MaxValue / 10 && value <= this.MaxValue / 10 * 2)
                return Brushes.Red;
            else if (value > this.MaxValue / 10 * 2 && value <= this.MaxValue / 10 * 3)
                return Brushes.DarkViolet;
            else if (value > this.MaxValue / 10 * 3 && value <= this.MaxValue / 10 * 4)
                return Brushes.Violet;
            else if (value > this.MaxValue / 10 * 4 && value <= this.MaxValue / 10 * 5)
                return Brushes.DarkBlue;
            else if (value > this.MaxValue / 10 * 5 && value <= this.MaxValue / 10 * 6)
                return Brushes.Blue;
            else if (value > this.MaxValue / 10 * 6 && value <= this.MaxValue / 10 * 7)
                return Brushes.DarkOrange;
            else if (value > this.MaxValue / 10 * 7 && value <= this.MaxValue / 10 * 8)
                return Brushes.Orange;
            else if (value > this.MaxValue / 10 * 8 && value <= this.MaxValue / 10 * 9)
                return Brushes.DarkGreen;
            else if (value > this.MaxValue / 10 * 9 && value <= this.MaxValue)
                return Brushes.Green;
            return Brushes.Black;
        }
        private void GetDiagramMaxMinValues()
        {
            if (DrowingElements != null)
            {
                this.MaxValue = 0;
                this.MinDate = DateTime.MaxValue;
                this.MaxDate = DateTime.MinValue;

                foreach (var item in DrowingElements.GroupBy(x => DateTime.Parse(x.Date.Value.ToShortDateString())))
                {
                    var time = new LogTime();
                    foreach (var log in item)
                        time.Add(log.Time);

                    this.MaxValue = MaxValue < time.GetSecond() ? time.GetSecond() : MaxValue;

                    MaxDate = MaxDate < item.Key ? item.Key : MaxDate;
                    MinDate = MinDate > item.Key ? item.Key : MinDate;
                }

                this.MaxValues = Money.Calculate(
                                    new LogTime(int.Parse(this.MaxValue.ToString().Split(new char[] { '.', ',' })[0])),
                                    MainConf.Setting.CashPerH,
                                    MainConf.Currencys,
                                    MainConf.Setting.CurrencyType);

                this.MaxValue = this.MaxValues.FirstOrDefault(x => x.Key == Utilities.GetEnum<CurrencyType>((string)CBValues.SelectedItem)).Value;
            }
        }
        private void CBValues_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (DrowingElements != null)
                DrowingElements = null;

            GetDiagramMaxMinValues();
            Initialize(new List<InitializeType>() {
                InitializeType.Diagram,
                InitializeType.ValuesDiagram
            });
        }
        private void dateTimePicker2_ValueChanged(object sender, EventArgs e)
        {
            if (DrowingElements != null)
                DrowingElements = null;
            GetDiagramMaxMinValues();
            Initialize(new List<InitializeType>() {
                InitializeType.Diagram,
                InitializeType.ValuesDiagram,
                InitializeType.Detail
            });
        }
        private void dateTimePicker1_ValueChanged(object sender, EventArgs e)
        {
            if (DrowingElements != null)
                DrowingElements.Clear();
            GetDiagramMaxMinValues();
            Initialize(new List<InitializeType>() {
                InitializeType.Diagram,
                InitializeType.ValuesDiagram,
                InitializeType.Detail
            });
        }
        private void PBCashValue_Paint(object sender, PaintEventArgs e)
        {
            if (DrowingElements != null)
            {
                var font = FontFamily.Families.FirstOrDefault(x => x.Name == "Axure Handwriting");
                e.Graphics.DrawString((Math.Round(this.MaxValue)).ToString(), new Font(font, 9, FontStyle.Bold), GetBrush(int.Parse((this.MaxValue).ToString().Split(new char[] { '.', ',' })[0]), false), new PointF(0, 0));
                e.Graphics.DrawString((Math.Round(this.MaxValue / 10 * 9)).ToString(), new Font(font, 9, FontStyle.Bold), GetBrush(int.Parse((this.MaxValue).ToString().Split(new char[] { '.', ',' })[0]) / 10 * 9, false), new PointF(0, PBCashValue.Height / 10));
                e.Graphics.DrawString((Math.Round(this.MaxValue / 10 * 8)).ToString(), new Font(font, 9, FontStyle.Bold), GetBrush(int.Parse((this.MaxValue).ToString().Split(new char[] { '.', ',' })[0]) / 10 * 8, false), new PointF(0, PBCashValue.Height / 10 * 2));
                e.Graphics.DrawString((Math.Round(this.MaxValue / 10 * 7)).ToString(), new Font(font, 9, FontStyle.Bold), GetBrush(int.Parse((this.MaxValue).ToString().Split(new char[] { '.', ',' })[0]) / 10 * 7, false), new PointF(0, PBCashValue.Height / 10 * 3));
                e.Graphics.DrawString((Math.Round(this.MaxValue / 10 * 6)).ToString(), new Font(font, 9, FontStyle.Bold), GetBrush(int.Parse((this.MaxValue).ToString().Split(new char[] { '.', ',' })[0]) / 10 * 6, false), new PointF(0, PBCashValue.Height / 10 * 4));
                e.Graphics.DrawString((Math.Round(this.MaxValue / 10 * 5)).ToString(), new Font(font, 9, FontStyle.Bold), GetBrush(int.Parse((this.MaxValue).ToString().Split(new char[] { '.', ',' })[0]) / 10 * 5, false), new PointF(0, PBCashValue.Height / 10 * 5));
                e.Graphics.DrawString((Math.Round(this.MaxValue / 10 * 4)).ToString(), new Font(font, 9, FontStyle.Bold), GetBrush(int.Parse((this.MaxValue).ToString().Split(new char[] { '.', ',' })[0]) / 10 * 4, false), new PointF(0, PBCashValue.Height / 10 * 6));
                e.Graphics.DrawString((Math.Round(this.MaxValue / 10 * 3)).ToString(), new Font(font, 9, FontStyle.Bold), GetBrush(int.Parse((this.MaxValue).ToString().Split(new char[] { '.', ',' })[0]) / 10 * 3, false), new PointF(0, PBCashValue.Height / 10 * 7));
                e.Graphics.DrawString((Math.Round(this.MaxValue / 10 * 2)).ToString(), new Font(font, 9, FontStyle.Bold), GetBrush(int.Parse((this.MaxValue).ToString().Split(new char[] { '.', ',' })[0]) / 10 * 2, false), new PointF(0, PBCashValue.Height / 10 * 8));
                e.Graphics.DrawString((Math.Round(this.MaxValue / 10)).ToString(), new Font(font, 9, FontStyle.Bold), GetBrush(int.Parse((this.MaxValue).ToString().Split(new char[] { '.', ',' })[0]) / 10, false), new PointF(0, PBCashValue.Height / 10 * 9));
                e.Graphics.DrawString("0", new Font(font, 9, FontStyle.Bold), GetBrush(0, false), new PointF(0, PBCashValue.Height - 15));
            }
        }
        private void PBDate_Paint(object sender, PaintEventArgs e)
        {
            if (DrowingElements != null)
            {
                GetDiagramMaxMinValues();
                var items = DrowingElements.GroupBy(x => DateTime.Parse(x.Date.Value.ToShortDateString())).OrderBy(x => x.Key);

                var step = Math.Round(items.Count() / 10.0);
                step = step < 1 ? 1 : step;

                var width = (PBDiagram.Width - 15) / items.Count();
                width = width < 80 ? 80 : width;

                var datelist = new List<DateTime>();
                foreach (var item in items)
                    datelist.Add(item.Key);

                var font = FontFamily.Families.FirstOrDefault(x => x.Name == "Axure Handwriting");

                for (int i = 0; i < (items.Count() < 10 ? items.Count() : 10); i++)
                {
                    e.Graphics.DrawString(
                        LogDate.GetFormatedDate(datelist[(i * Utilities.ParseToInt(step) > items.Count() - 1 ? items.Count() - 1 : i * Utilities.ParseToInt(step))].ToShortDateString(), FormateDate.DayMonth),
                        new Font(font, 9, FontStyle.Bold),
                        Brushes.Red,
                        new PointF(width * i + 6, 0));
                }
            }

        }

        private void BtClose_Click(object sender, EventArgs e)
        {
            this.Close();
        }
        private void BtInDock_Click(object sender, EventArgs e)
        {
            this.WindowState = FormWindowState.Minimized;
        }
        private void panel1_MouseDown(object sender, MouseEventArgs e)
        {

            this.MouseClick = true;
            this.MouseClickPosition = new Point(e.Location.X, e.Location.Y);
        }
        private void panel1_MouseUp(object sender, MouseEventArgs e)
        {
            this.MouseClick = false;
            this.MouseClickPosition = Point.Empty;
        }
        private void panel1_MouseMove(object sender, MouseEventArgs e)
        {
            if (this.MouseClick)
            {
                this.Top = MousePosition.Y - this.MouseClickPosition.Y;
                this.Left = MousePosition.X - this.MouseClickPosition.X;
            }
        }
    }
}
